首页
学习
活动
专区
圈层
工具
发布

简单实现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求反的意思。

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

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

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

    1.5K30

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

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

    82110

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

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

    50840

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

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

    50660

    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,具体是什么意思呢?

    2.3K20

    浅谈MDK, IAR,CLANG和GCC的局部变量字节对齐处理差异(2023-10-13)

    视频: https://www.bilibili.com/video/BV1CB4y1Z7kA 问题由来: 早期这个帖子里面的局部变量对齐仅测试了MDK AC5,但项目中使用AC6发现了新问题,看来...上面这个贴图最重要,仅需理解上面这两条就可以,意思是说,栈地址是全程至少保持4字节对齐的,因为M内核的硬件长做了处理,SP最低两个bit,bit0和bit1直接固定为0了。...以xxx.S启动文件为例,通过伪指令PRESERVE8来保证 那么问题来了,我们搞个4对齐是不是会出问题,一般情况下也没问题的,但特殊情况下不行,特别调用C库的sprintf和printf函数,直接给你输出个不知所以然的结果来...比如我在H7上做如下测试: 输出结果: 总结: MDK AC5和IAR的用法差不多,MDK AC6和GCC的用法差不多视频里面做了详细对比测试)。

    18110

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

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

    1.3K21

    【汇编语言】和loop指令(一)—— 初识和loop指令

    概念引入 1.1 [bx]和内存单元的描述 [bx]是什么呢? 和[0]有些类似,[0]表示内存单元,它的偏移地址是0。...比如在下面的指令中(但是注意这个是在 Debug 中使用的方式): 1.1.1 示例1 mov ax, [0] 将一个内存单元的内容送入 ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为...该指令执行后,ax=00beH。 (3)接下来,第5、6条指令: inc bx inc bx 这两条指令执行前 bx=1000H,执行后bx=1002H。...(5)接下来,第8、9条指令: inc bx inc bx 这两条指令执行前 bx=1002H,执行后bx=1004H。...从上面的描述中,可以看到,cx中的值影响着loop指令的执行结果。通常(注意,我们说的是通常)我们用loop指令来实现循环功能,cx中存放循环次数。

    1.6K10

    处理器的乱序执行

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

    1.6K60

    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来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法

    28530

    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的内容: ?

    3.4K10

    【操作系统】考研408操作系统核心考点:进程控制机制与原语实现深度解析​

    理解了进程状态的“是什么”和“为什么”后,我们很自然会问: 操作系统是如何精准控制这些状态转换的? 进程是如何被创建、终止和调度的? 这些状态转换背后需要怎样的机制来保障其可靠性和一致性?...这两条指令的作用分别为: 关中断——使 CPU ​​暂时不响应​​(或忽略)可屏蔽的中断请求 开中断——使 CPU ​​恢复响应​​可屏蔽中断请求 这里我们通过一个简单的例子进行说明: 经过前面的学习,...,会屏蔽所有的可屏蔽中断请求; 当 CPU 执行了开中断之后,会重新开始进行中断信号的检测,继续回到 每执行一条指令,就检测一次中断信号 的状态; 正是因为这两条特权指令,这就确保了这两条指令中间所有指令的原子性...,就比如上图中的指令2和指令3; 下面我们需要思考一个问题——为什么开中断与关中断属于特权指令?...原语作为操作系统底层具有原子性的公用小程序,通过​​关中断​​和​​开中断​​这两条特权指令,确保了进程状态转换操作的完整性和一致性。

    27910

    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位置上的

    87720

    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位置上的

    73420

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

    而帧指针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所指的内存中

    4.7K21

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

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

    41110

    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后标签处 这两条汇编指令相当于

    60320

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

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

    69040
    领券