首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

简单实现posix规定的memcmp函数

简介 memcmp函数的功能非常简单,传入两个指针s1和s2,以及要比较的字节大小n,比较这两块内存的值的差异(逐字节比较,把每个字节都翻译为unsigned char)。...我们使用repe和cmpsb这两条指令来实现。 repz指令是一个循环指令,每次循环会不断的递减rcx寄存器内的值,当rcx为0或处理器的zero flag不为1时,退出循环。...cmpsb指令则是对两个字节作比较的指令,在计算结束后,会设置相应的状态标志位。cmpsb指令涉及到的两个操作数分别存在rdi、rsi寄存器。在操作结束后,如果这两个操作数的值相同,则会将ZF置位。...而输出nz到diff,因此输出的是0. 如果某一字节不相同,那么diff=1。再在下面计算这两个字节到底相差了多少,然后就出结果了。...上面的nz就是对ZF求反的意思。

64250
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    精致全景图 | 系统调用是如何实现的

    在系统调用函数执行完毕之后,执行结果会被放到rax寄存器。 最后,执行sysret汇编指令,从内核态切换回用户态,用户程序继续执行。 如果用户程序需要该系统调用的返回结果,则从rax获取。...总体流程就是这样,相对来说,还是比较简单的,主要就是先去理解syscall和sysret这两条汇编指令,在理解这两条汇编指令的基础上,再去看内核源码,就会容易很多。...以write系统调用为例,其对应的内核源码为: 在内核,所有的系统调用函数都是通过 SYSCALL_DEFINE 等宏定义的,比如上面的write函数,使用的是 SYSCALL_DEFINE3。...再看上面的压栈过程,每一次压栈操作我们都可以认为是在分配内存空间并赋值,当r15被最终压入到栈后,整个内存空间分配完毕,且数据也初始化完毕,此时,rsp指向的栈顶地址,就是这段内存空间的最小地址,因为压栈过程...如果对上面的汇编不太理解,可以把它想像成下面这个样子: 在这里,我们使用的是glibc的write方法来执行该系统调用,其实该方法就是对syscall指令做的一层封装,本质上使用的还是我们上面的汇编代码

    1.1K30

    精准解析 useLayoutEffect 与 useEffect 的执行时机

    第一个参数 layoutEffect 为一个函数,定义为副作用执行逻辑,我们也可以在 layoutEffect 定义返回函数。...这里组件渲染完成的意思是当组件内容已经呈现在页面上之后,effect 再执行,具体的步骤如下图所示 在事件循环中, effect 是被定义为宏任务,在下一轮循环执行 然后是 useLayoutEffect...() layoutEffect 紧随 DOM 修改指令发出之后执行,此时虽然 DOM 指令已经发出,但是在浏览器的机制,内容绘制是一个异步的过程,这会儿绘制并没有执行 因此在事件循环中,layoutEfect...被定义为类似于 Promise 的微任务,在 DOM 指令修改之后,内容绘制之前执行 后续影响 大家可以猜想一下,如果我们在 layoutEffect 中直接去修改 state,会发生什么事情 看看下面这个例子...UI 发出了两条不同的指令,在浏览器的渲染机制,也会发生收集行为,将这两条指令进行合并,最后只执行一条 // setCount(0) div.innerHTML = 0 // setCount(1

    41110

    Linux内核同步机制之(一):原子操作

    在多CPU体系结构,运行在两个CPU上的两个内核控制路径同时并行执行上面操作序列,有可能发生下面的场景: ?...从上面的定义来看,atomic_t实际上就是一个int类型的counter,不过定义这样特殊的类型atomic_t是有其思考的:内核定义了若干atomic_xxx的接口API函数,这些函数只会接收atomic_t...(4)我们先看ldrex和strex这两条汇编指令的使用方法。ldr和str这两条指令大家都是非常的熟悉了,后缀的ex表示Exclusive,是ARMv7提供的为了实现同步的汇编指令。...其实,在执行这条指令的时候,还放出两条“狗”来负责观察特定地址的访问(就是保存在[]的地址了),这两条狗一条叫做local monitor,一条叫做global monitor。...%0对应output openrand list的"=&r" (result),=表示该操作数是write only的,&表示该操作数是一个earlyclobber operand,具体是什么意思呢?

    2K20

    MySQL实战第四十四讲- 要不要使用分区表?

    那么,为什么语句 Q1 和 Q2 这两个查询的执行流程会差距这么大呢?其实,这是因为优化器基于 Q2 这个查询的语义做了优化。...而这就是 distinct 的语义,所以不需要执行聚合函数时,distinct 和 group by 这两条语句的语义和执行流程是相同的,因此执行性能也相同。 这两条语句的执行流程是下面这样的。...而至于为什么不会发生不一致的情况,我们来看一下下面的这个例子。...小结 今天这篇答疑文章,我选了 4 个好问题和你分享,并做了分析。在我看来,能够提出好问题,首先表示这些同学理解了我们文章的内容,进而又做了深入思考。...你可以通过实验验证一下,然后分析看看,事务 id 的分配规则是什么,以及 MySQL 为什么要这么设计呢? PS:这个问题将会在下一篇文章给予解答。

    32740

    MySQL实战第四十四讲- 答疑文章:说一说这些好问题

    那么,为什么语句 Q1 和 Q2 这两个查询的执行流程会差距这么大呢?其实,这是因为优化器基于 Q2 这个查询的语义做了优化。...而这就是 distinct 的语义,所以不需要执行聚合函数时,distinct 和 group by 这两条语句的语义和执行流程是相同的,因此执行性能也相同。 这两条语句的执行流程是下面这样的。...而至于为什么不会发生不一致的情况,我们来看一下下面的这个例子。...小结 今天这篇答疑文章,我选了 4 个好问题和你分享,并做了分析。在我看来,能够提出好问题,首先表示这些同学理解了我们文章的内容,进而又做了深入思考。...你可以通过实验验证一下,然后分析看看,事务 id 的分配规则是什么,以及 MySQL 为什么要这么设计呢? PS:这个问题将会在下一篇文章给予解答。

    32960

    go语言调度器源代码情景分析之五:汇编指令

    不过,虽然这里的介绍做了精简,但读者大可放心,熟练运用这些知识就足以应付本书将要分析的goroutine调度器的汇编代码了。...调度器,因此下面我们只介绍该平台下所使用的AT&T格式的汇编指令,AT&T汇编指令的基本格式为: 操作码 [操作数] 可以看到每一条汇编指令通常都由两部分组成: 操作码:操作码指示CPU执行什么操作,...所以上面这条指令表示对rax和rdx寄存器里面的值求和,并把结果保存在rax寄存器。...ret指令从被调用函数返回调用函数,它的实现原理是把call指令入栈的返回地址弹出给rip寄存器。 下面用例子对这两条指令的原理加以说明。...被调用函数在0x40053f处执行retq指令返回调用函数继续执行0x40055e地址处的指令。注意这两条指令会涉及入栈和出栈操作,所以会影响rsp寄存器的值。 ?

    1.1K21

    处理器的乱序执行

    2.指令调度 在前面乱序设置陷阱的例子,如果没有那个聪明的士兵,乱序也就无从谈起。同样,处理器的乱序执行内核也需要一个调度器,分析指令间的相关性,分析指令什么时候能开始执行。...指令什么时候能开始执行呢? 对于一条指令来说,它有操作码和操作数,操作码描述指令要做什么,处理器会安排个功能单元( function unit)去执行它。...(2) 该指令的源操作数是否已经准备好。 只要满足这两条要求,指令就可以去执行,而不需要等待前面的指令完成。这样处理器就完成了乱序调度及并行调度。 以前面经过寄存器重命名的指令为例, ?...3.指令的顺序提交 在指令的执行过程,通常会有中断和异常产生,如在下面的这个例子, ?...乱序执行后,指令的结果虽然出来了,但是这个结果并没有立即提交到ISA寄存器,而是先缓存起来,只有当前指令面的指令提交后,这条指令才能提交。

    1.4K60

    Java并发篇_synchronized

    本文给大家介绍java的用法。 一、为什么要使用synchronized 在并发编程存在线程安全问题,主要原因有: 1.存在共享数据 2.多线程共同操作共享数据。...synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性 二、synchronized的用法 synchronized可以修饰静态方法、成员函数...synchronized (this) { System.out.println("Method 1 start"); } } } 反编译结果: 关于这两条指令的作用...,我们应该能很清楚的看出Synchronized的实现原理,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法才能调用...; 6 } 7 } 反编译结果: 从反编译的结果来看,方法的同步并没有通过指令monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法

    16230

    Wireshark的HTTP请求包和响应包如何对应

    以Wireshark2.6.3版本为例,如下图所示,红框的803是一次HTTP的GET请求包,绿框的809、810两条记录都是响应包,究竟哪个是803的响应包呢?...通过传输控制协议信息识别 如下图,点击803这条记录后,在下面的详情窗口打开传输层信息,查看Next sequence number字段的值为282: ?...分别打开809、810这两条记录的详情,查看它们的传输层信息,找到Acknowledgment number字段,等于282的记录就是803的响应信息,如下图: ?...此时已经找到了803对应的响应,可以继续打开HTTP层的数据查看响应信息的详情了; 通过Wireshark的识别结果 通过传输控制协议信息识别的方法略有些麻烦,需要打开所有记录逐个检查,Wireshark已经做了更方便的方式...查看响应数据时也有对应的请求包链接,双击链接可打开对应的请求数据包,如下图,以809号记录为例,在HTTP层可以双击下图红框的内容,直接打开803的内容: ?

    2.6K10

    golang | 各种channel操作的底层实现

    p函数的参数是通过ax寄存器传递的,由上图可见,在调用p函数之前,ax寄存器的值,通过xorl指令进行了清零,这也是channel变量的nil值,在底层是用0表示的另一个佐证。...在看runtime.makechan函数之前,我们先通过上图的汇编,看下make创建unbuffered channel和buffered channel的方式有什么不同。...由上图可见,对channel的len和cap操作,在汇编层面都是一条mov指令,并不像之前的,比如对channel的接收操作,是转换成对runtime.chanrecv1函数的调用,且在该函数,有加锁解锁操作...那为什么这两条mov指令,就可以获得channel的len和cap值呢? 首先看上图汇编,13行的ax和21行的cx,存放的都是新建channel结构体的地址。...那这两条mov指令的意思是: MOVQ 0(AX), CX -> 将channel结构体偏移量为0位置上的8字节放入cx MOVQ 0x8(CX), CX -> 将channel结构体偏移量为8位置上的

    65220

    golang | 各种channel操作的底层实现

    p函数的参数是通过ax寄存器传递的,由上图可见,在调用p函数之前,ax寄存器的值,通过xorl指令进行了清零,这也是channel变量的nil值,在底层是用0表示的另一个佐证。...在看runtime.makechan函数之前,我们先通过上图的汇编,看下make创建unbuffered channel和buffered channel的方式有什么不同。...由上图可见,对channel的len和cap操作,在汇编层面都是一条mov指令,并不像之前的,比如对channel的接收操作,是转换成对runtime.chanrecv1函数的调用,且在该函数,有加锁解锁操作...那为什么这两条mov指令,就可以获得channel的len和cap值呢? 首先看上图汇编,13行的ax和21行的cx,存放的都是新建channel结构体的地址。...那这两条mov指令的意思是: MOVQ 0(AX), CX -> 将channel结构体偏移量为0位置上的8字节放入cx MOVQ 0x8(CX), CX -> 将channel结构体偏移量为8位置上的

    58720

    函数调用时栈是如何变化的?

    而帧指针rbp是不移动的,访问栈的元素可以用-4(%rbp)或者8(%rbp)访问%rbp指针下面或者上面的元素。...函数调用时 进入sum函数后,我们看到函数的前两行: push %rbp mov %rsp,%rbp 这两条汇编指令的含义是:首先将rbp寄存器入栈,然后将栈顶指针rsp赋值给rbp。...eax,第二条指令将eax的值存入局部变量c所在的内存,第三条指令将局部变量c的值读取到eax,可以看到,局部变量c被编译器安排到了%rbp -0x4这个地址对应的内存。...接下来继续执行 pop %rbp retq 这两条指令的功能相当于下面的指令: mov %rbp,%rsp pop %rbp pop %rip 即在操作上面两条指令的时候,首先把rsp赋值,它的值是存储调用函数...函数调用后 函数最后返回的时候,继续执行下面这条指令: mov %eax,-0x4(%rbp) # 把sum函数的返回值赋给变量z 上述指令将eax的结果放入rbp -0x4所指的内存

    3.2K21

    01-C语言进阶篇与常见面试题笔记

    01.工具原理及C语言语法基础 1.1 - 计算机指令概述及C语言如何学 计算机工作方式简介 可以把内存暂且人认为是存储指令的仓库,cpu从仓库取出指令一条条执行,cpu需要通过地址找到内容,所以需要一个地址线...内存成本高,速度快 外存成本低,速度慢,但是容量大 问题:CPU里的指令什么样?...在wingwinclude的头文件在哪里? 注意:WinGW的工具链有时可能不是放在根目录的include文件,而是放在下面的工具目录,有的版本可能放在根目录。...cc1.exe程序生成了ccfJngfc.s汇编文件(注意与第一节课的arm汇编体系不是一个体系) 下一步gcc做了个头文件的处理,详情见后面章节 之后gcc使用了as.exe程序将ccfJngfc.s...翻译官的工作流程 02.C语言空间操作篇 2.1 - 数字进制表示法01 03.C语言函数设计篇 04.C语言常见面试题篇

    31010

    Android逆向08 IDA爆破签名验证

    ---- 一 翻开导出表窗口(Exports) 1.用apktool解包apk后用IDA翻开libJniTest.so 上面引见两个窗口: (1)Exports窗口是导出表(so能让内部调用的函数)...(2)Imports窗口是导入表(so调用到里面的函数) 2.经过剖析java层晓得顺序调用了一个native层函数check 既然晓得了Exports窗口能罗列出so中被内部调用的一切函数 又晓得natve...函数check是在java层被调用的 所以翻开导出表窗口 搜索check 经过第6课晓得 so函数都是java_包名类名_办法名格式的 所以这里check函数就被找到了 3.双击出来检查check办法...选中上面的函数 右键Force call type 7 其他的函数也都这样做 然后点住a1按住n键重命名为env 至于为什么这样做 这不是本节课的重点 当前的课程中会讲到的 8.当前的课程会有JNI的编写...否则跳到右视图加入顺序 BNE: 数据跳转指令,标志寄存器Z标志位不等于零时, 跳转到BNE后标签处 BEQ: 数据跳转指令,标志寄存器Z标志位等于零时, 跳转到BEQ后标签处 这两条汇编指令相当于

    39020

    什么处理排序的数组要比非排序的快

    ---- 我首先得想法是排序把数据放到了cache,但是我下一个想法是我之前的想法是多么傻啊,因为这个数组刚刚被构造。 到底这是为什么呢? 为什么排序的数组会快于没有排序的数组?...(completely random - hard to predict) ---- 我们能做些什么呢 如果编译器无法优化带条件的分支,如果你愿意牺牲代码的可读性换来更好的性能的话,你可以用下面的一些技巧...当CPU正在执行(execute)指令A时,CPU的其他处理单元(CPU是由若干部件构成的)其实已经预先处理到了指令A后面的指令,例如B可能已经被解码,C已经被取指。...这就是流水线执行,这可以保证CPU高效地执行指令。 分支预测 如上所说,CPU在执行一堆顺序执行的指令时,因为对于执行指令的部件来说,其基本不需要等待,因为诸如取指、解码这些过程早就被做了。...所以,取指解码这些单元就会继续取跳转指令之后的指令。当CPU执行到跳转指令时,如果真的发生了跳转,那么之前的预处理(取指、解码)就白做了

    49140

    【Java】【并发编程】详解并发三大特性

    一、原子性 什么是原子性:就是指一个操作是不可中断的,要么执行成功要么执行失败,在多线程,一个线程正在执行就不会被其他线程干扰。...对语句3,4的分析同理可得这两条语句不具备原子性。当然,java内存模型定义了8操作都是原子的,不可再分的。...(读取):作用于主内存的变量,它把一个变量的值从主内存复制传输到线程的工作内存,以便后面的load动作使用; load(载入):作用于工作内存的变量,它把read操作从主内存得到的变量值复制放入工作内存的变量副本...上面的这些指令操作是相当底层的,可以作为扩展知识面掌握下。那么如何理解这些指令了?...同样的在volatile分析,会通过在指令添加内存屏障指令,以实现内存可见性。

    76400

    Java volatile修饰符的用法及作用详解版

    而编译器的乱序,作为编译优化的一种手段,则试图通过指令重排,在这两条指令之间插入其他指令,将这两条指令拉开一定的距离,以保证后一条指令执行的时候前一条指令结果已经得到了,那么也就不需要阻塞等待了。...所以相比于CPU的乱序,编译器的乱序才是真正对指令顺序做了调整,但是编译器所进行的调整也必须保证上下文的依赖逻辑,即存在依赖关系的指令顺序不能调整。...,也不会把前面的指令排到内存屏障的后面; 2)、它会强制将对缓存的修改操作(操作完成后)立即写入主存; 3)、如果是写操作,它会导致其他CPU对应的缓存行无效。...这里你可能会疑惑,你会觉得根据前面的说法,当线程2完成自增操作并写回主存后不是会使得其他线程对该变量的缓存无效么,那为什么线程1没有去重新读取呢?...,线程2调用decrease()函数

    51630
    领券